#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jun  9 15:11:48 2025

@author: fenghongli
"""
#构建网络图对象

import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import community as community_louvain
import numpy as np
import matplotlib.cm as cm


# 读取FEVD贡献矩阵（N×N）
spill_matrix = pd.read_csv("dy_spillover_matrix.csv", index_col=0)

# 构建有向图（节点 = 资产，边 = 溢出贡献）
G = nx.DiGraph()

# 添加节点
for node in spill_matrix.columns:
    G.add_node(node)

# 添加有向边（带权重）
for i in spill_matrix.index:
    for j in spill_matrix.columns:
        weight = spill_matrix.loc[i, j]
        if weight > 0:  # 可以设置阈值过滤弱边，如 weight > 0.01
            G.add_edge(i, j, weight=weight)

print(f"网络构建完成：共 {G.number_of_nodes()} 个节点，{G.number_of_edges()} 条边")

# Degree 中心性（出度 / 入度）
out_degree = dict(G.out_degree(weight='weight'))
in_degree = dict(G.in_degree(weight='weight'))

# PageRank 中心性（衡量“传播力”）
pagerank = nx.pagerank(G, weight='weight')

# Betweenness 中心性（桥梁节点）
betweenness = nx.betweenness_centrality(G, weight='weight')

# 打包为DataFrame
centrality_df = pd.DataFrame({
    '资产': list(G.nodes),
    'Out-Degree': [out_degree[node] for node in G.nodes],
    'In-Degree': [in_degree[node] for node in G.nodes],
    'PageRank': [pagerank[node] for node in G.nodes],
    'Betweenness': [betweenness[node] for node in G.nodes]
})

# 排序查看“风险超级传播者”
centrality_df_sorted = centrality_df.sort_values(by='PageRank', ascending=False)
centrality_df_sorted.to_csv("node_centrality.csv", index=False)
print("中心性指标计算完成，前几名如下：")
print(centrality_df_sorted.head())

# 网络可视化

# 创建位置布局（spring布局常用于有向加权网络）
pos = nx.spring_layout(G, seed=42)

# 提取中心性指标
pagerank = nx.pagerank(G, weight='weight')
out_degree = dict(G.out_degree(weight='weight'))

# 节点颜色：PageRank（传播力），用颜色深浅表示
node_color = [pagerank[node] for node in G.nodes]

# 节点大小：Out-Degree（输出风险强度），乘以一个缩放因子
node_size = [out_degree[node] * 800 for node in G.nodes]

# 边权重：溢出强度（边粗细）
edge_weights = [G[u][v]['weight'] * 8 for u, v in G.edges]

# 画图
plt.figure(figsize=(10, 8))
nx.draw_networkx_nodes(G, pos, node_color=node_color, node_size=node_size, cmap=plt.cm.Oranges)
nx.draw_networkx_edges(G, pos, width=edge_weights, arrows=True, edge_color='gray', alpha=0.6)
nx.draw_networkx_labels(G, pos, font_size=10)

plt.title("Financial-Real Estate Risk Spillover Network Diagram", fontsize=16)
plt.axis('off')
plt.tight_layout()
plt.savefig("network_visualization.png", dpi=300)
plt.show()


# 将有向图转为无向图（Louvain 只能处理无向图）
G_undirected = G.to_undirected()

# 使用 Louvain 算法进行社区划分
partition = community_louvain.best_partition(G_undirected, weight='weight')

# 将社区编号添加为节点属性
nx.set_node_attributes(G, partition, 'community')

# 打印各资产对应的社区编号
print("社区划分结果：")
for node, comm in partition.items():
    print(f"{node}: 社区 {comm}")

# 保存社区信息表
community_df = pd.DataFrame({
    '资产': list(partition.keys()),
    '社区编号': list(partition.values())
})
community_df.to_csv("node_community.csv", index=False)


# 用不同颜色表示不同社区

# 获取所有社区编号
communities = set(partition.values())
color_map = cm.rainbow(np.linspace(0, 1, len(communities)))
node_colors = [color_map[partition[node]] for node in G.nodes]

plt.figure(figsize=(10, 8))
nx.draw_networkx_nodes(G, pos, node_color=node_colors, node_size=800)
nx.draw_networkx_edges(G, pos, arrows=True, edge_color='gray', alpha=0.5)
nx.draw_networkx_labels(G, pos, font_size=10)

plt.title("Louvain Community division results", fontsize=16)
plt.axis('off')
plt.tight_layout()
plt.savefig("louvain_community_plot.png", dpi=300)
plt.show()
